﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace Cabal.Kernel.Provider
{
    public class BSControl:IResControl,IDisposable
    {
        public BSControl(CabalSoul kernel,string path)
        {
            _kernel = kernel;
            _path = path;
            _support = _kernel.Support;
            init();
        }



        const string Regid_BSControl = "BS.XML";
        const string XPath_BSRoot = "CabalSoul/BSCollection";
        const string XPath_BSUseabelRoot = "CabalSoul/BSCollection/UseableBS";
        const string XPath_BSUsedRoot = "CabalSoul/BSCollection/UsedBS";
        const string XPath_Nomal = "Nomal";
        const string XPath_Verify = "Verify";
        const string XPath_NomalA = "/Nomal";
        const string XPath_VerifyA = "/Verify";
        const string XPath_BSItem = "BS";

        CabalSoul _kernel;
        EnvSupport _support;
        string _path;

        List<BS> ua_verf = new List<BS>();
        List<BS> ua_nmal = new List<BS>();
        List<BS> ud_verf = new List<BS>();
        List<BS> ud_nmal = new List<BS>();

        /// <summary>
        /// 把验证码BS视为普通BS（当获取普通BS用尽的时候就获取验证码BS，默认为false，不使用验证码BS）
        /// </summary>
        public bool BS_NomalBelongVerify = false;
        /// <summary>
        /// 实时整理BS（会使计算剩余数量更警觉，但耗费资源。默认为FLASE，不实时整理BS）
        /// </summary>
        public bool BS_RealTimeCollator = false;




        void init()
        {
            _kernel.Support.Register(Regid_BSControl, _path);
            load();
        }
        void load()
        {
            XmlNode useable_verf = _support.ReadNode(Regid_BSControl, XPath_BSUseabelRoot + XPath_VerifyA);
            XmlNode useable_nmal = _support.ReadNode(Regid_BSControl, XPath_BSUseabelRoot + XPath_NomalA);
            XmlNode used_verf = _support.ReadNode(Regid_BSControl, XPath_BSUsedRoot + XPath_VerifyA);
            XmlNode used_nmal = _support.ReadNode(Regid_BSControl, XPath_BSUsedRoot + XPath_NomalA);

            ua_nmal.Clear();
            ua_verf.Clear();
            ud_nmal.Clear();
            ud_verf.Clear();

            BS tmp;
            foreach (XmlNode i in useable_verf.ChildNodes)
            {
                tmp = new BS(i);
                AddBS(tmp, tmp.UseableVerify, true);
            }
            foreach (XmlNode i in useable_nmal.ChildNodes)
            {
                tmp = new BS(i);
                AddBS(tmp, tmp.UseableNomal, false);
            }
            foreach (XmlNode i in used_verf.ChildNodes)
            {
                tmp = new BS(i);
                AddBS(tmp, tmp.UseableVerify, true);
            }
            foreach (XmlNode i in used_nmal.ChildNodes)
            {
                tmp = new BS(i);
                AddBS(tmp, tmp.UseableNomal, false);
            }
            tmp = null;
        }
        void save2xml()
        {
            XmlNode useable_verf = _support.ReadNode(Regid_BSControl, XPath_BSUseabelRoot + XPath_VerifyA);
            XmlNode useable_nmal = _support.ReadNode(Regid_BSControl, XPath_BSUseabelRoot + XPath_NomalA);
            XmlNode used_verf = _support.ReadNode(Regid_BSControl, XPath_BSUsedRoot + XPath_VerifyA);
            XmlNode used_nmal = _support.ReadNode(Regid_BSControl, XPath_BSUsedRoot + XPath_NomalA);

            useable_verf.RemoveAll();
            useable_nmal.RemoveAll();
            used_verf.RemoveAll();
            used_nmal.RemoveAll();

            foreach (BS i in ua_verf)
            {
                XmlNode node = _support.CreatElement(Regid_BSControl, XPath_BSItem);
                i.ToXmlNode(node);
                used_verf.AppendChild(node);
            }
            foreach (BS i in ud_verf)
            {
                XmlNode node = _support.CreatElement(Regid_BSControl, XPath_BSItem);
                i.ToXmlNode(node);
                used_verf.AppendChild(node);
            }
            foreach (BS i in ua_nmal)
            {
                XmlNode node = _support.CreatElement(Regid_BSControl, XPath_BSItem);
                i.ToXmlNode(node);
                used_nmal.AppendChild(node);
            }
            foreach (BS i in ud_nmal)
            {
                XmlNode node = _support.CreatElement(Regid_BSControl, XPath_BSItem);
                i.ToXmlNode(node);
                used_nmal.AppendChild(node);
            }
        }
        void checkType(string type)
        {
            string lowType = type.ToLower();
            if (lowType != "bs" && lowType != "all")
                throw ResourceException.Request_UnknowType(this, type);
        }
        void collator()
        {
            collatorVerf();
            collatorNmal();
        }
        void collatorVerf()
        {
            for (int i = ua_verf.Count - 1; i >= 0; i--)
            {
                if (ua_verf[i].UseableVerify == false)
                    MoveBS(ua_verf[i], true);
            }
        }
        void collatorNmal()
        {
            for (int i = ua_nmal.Count - 1; i >= 0; i--)
            {
                if (ua_nmal[i].UseableNomal == false)
                    MoveBS(ua_nmal[i], false);
            }
        }
        public void MoveBS(BS bs, bool verf)
        {
            if (verf)
            {
                ua_verf.Remove(bs);
                ud_verf.Add(bs);
            }
            else
            {
                ua_nmal.Remove(bs);
                ud_nmal.Add(bs);
            }
        }

        public BS RequestBS()
        {
            try
            {
                return RequestBS(false);
            }
            catch (Exception err)
            {
                if (err is ResourceException)
                    return RequestBS(true);
                else
                    throw err;
            }
        }
        public BS RequestBS(bool VerifyBS)
        {
            return (VerifyBS) ? 
                    RequestVerifyBS() 
                  : RequestNomalBS();
        }
        BS RequestVerifyBS()
        {
            BS rtn;
            while (ua_verf.Count > 0)
            {
                rtn = ua_verf[0];
                if (rtn.UseableVerify)
                {
                    ua_verf.Remove(rtn);
                    ua_verf.Add(rtn);
                    return rtn;
                }
                else
                    MoveBS(rtn, true);
            }
            throw ResourceException.BS_VerifyEmpty;
        }
        BS RequestNomalBS()
        {
            BS rtn;
            while (ua_nmal.Count > 0)
            {
                rtn = ua_nmal[0];
                if (rtn.UseableNomal)
                {
                    ua_nmal.Remove(rtn);
                    ua_nmal.Add(rtn);
                    return rtn;
                }
                else
                    MoveBS(rtn, false);
            }
            if (BS_NomalBelongVerify)
            {
                while (ua_verf.Count > 0)
                {
                    rtn = ua_verf[0];
                    if (rtn.UseableVerify)
                    {
                        ua_verf.Remove(rtn);
                        ua_verf.Add(rtn);
                        return rtn;
                    }
                    else
                        MoveBS(rtn, true);
                }
                throw ResourceException.BS_AllEmpty;
            }
            else
            {
                throw ResourceException.BS_NomalEmpty;
            }
        }

        public void AddBS(BS bs)
        {
            if(bs.IsVerifyBS())
                AddBS(bs, bs.UseableVerify, true);
            else
                AddBS(bs, bs.UseableNomal, false);
        }
        public void AddBS(BS bs,bool useable, bool verf)
        {
            bs.Parent = this;
            if (useable)
            {
                if (verf) //验证码可用BS
                    ua_verf.Add(bs);
                else //普通可用BS
                    ua_nmal.Add(bs);
            }
            else
            {
                if (verf) //验证码用过BS
                    ud_verf.Add(bs);
                else //普通用过BS
                    ud_nmal.Add(bs);
            }
        }

        public bool RemoveBS(BS bs)
        {
            bool rtn = false;
            foreach (List<BS> i in new List<BS>[] { ua_verf, ua_nmal, ud_verf, ud_nmal })
            {
                rtn |= i.Remove(bs);
            }
            return rtn;
        }
        public bool RemoveBS(BS bs, bool useable, bool verf)
        {
            if (useable)
            {
                if (verf) //验证码可用BS
                    return ua_verf.Remove(bs);
                else //普通可用BS
                    return ua_nmal.Remove(bs);
            }
            else
            {
                if (verf) //验证码用过BS
                    return ud_verf.Remove(bs);
                else //普通用过BS
                    return ud_nmal.Remove(bs);
            }
        }

        public int BSCountUseableVerify
        {
            get
            {
                if(BS_RealTimeCollator)
                    collatorVerf();
                return ua_verf.Count;
            }
        }
        public int BSCountUseableNomal
        {
            get
            {
                if (BS_RealTimeCollator)
                    collatorNmal();
                return ua_nmal.Count;
            }
        }
        public int BSCountAllNomal
        {
            get { return ua_nmal.Count + ud_nmal.Count; }
        }
        public int BSCountAllVerify
        {
            get { return ua_verf.Count + ud_verf.Count; }
        }
        public int BSCountUseable
        {
            get
            {
                return BSCountUseableVerify + BSCountUseableNomal;
            }
        }
        public int BSCountAll
        {
            get
            {
                return ua_nmal.Count 
                     + ua_verf.Count 
                     + ud_nmal.Count 
                     + ud_verf.Count;
            }
        }


        #region IProvider 成员

        /// <summary>
        /// 请求资源
        /// </summary>
        /// <param name="type">资源类型(bs)</param>
        /// <param name="arg">参数: (string) "all"-任意BS "verify"-验证码BS "nomal"-普通BS</param>
        /// <returns></returns>
        public object Request(string type, object arg)
        {
            checkType(type);

            string bstype = ((string)arg).ToLower();
            switch (bstype)
            {
                case "all":
                    return (object)RequestBS();
                case "verify":
                    return (object)RequestBS(true);
                case "nomal":
                    return (object)RequestBS(false);
                default:
                    throw ResourceException.Request_ArgUnknow;
            }
        }

        public bool Reload(string type)
        {
            try
            {
                checkType(type);
                init();
                return true;
            }
            catch
            {
                return false;
            }
        }

        #endregion


        #region IResControl 成员

        /// <summary>
        /// 添加资源
        /// </summary>
        /// <param name="type">资源类型(bs)</param>
        /// <param name="arg">参数 (null)程序自动判断 (bool[2])item1是否可用 item2是否是验证码</param>
        /// <param name="data"></param>
        public void AddResource(string type, object arg, object data)
        {
            checkType(type);
            if (arg == null) //自动判断
            {
                AddBS((BS)data);
            }
            else
            {
                if ((arg is bool[]) && ((bool[])arg).Length == 2) //arg = {bool,bool}
                {
                    bool[] args = (bool[])arg;
                    AddBS((BS)data, args[0], args[1]);
                }
                else
                    throw ResourceException.Request_ArgUnknow;
            }
        }

        public void Remove(string type, object data)
        {
            checkType(type);
            RemoveBS((BS)data);
        }

        public void Clear(string type)
        {
            checkType(type);

            ua_verf.Clear();
            ua_nmal.Clear();
            ud_verf.Clear();
            ud_nmal.Clear();
        }

        public void Save()
        {
            save2xml();
            _support.Save(Regid_BSControl, _path);
        }

        #endregion


        #region IDisposable 成员

        public void Dispose()
        {
            _support.UnRegister(Regid_BSControl);
        }

        #endregion

        public override string ToString()
        {
            return "Cabal.Kernel.Provider.BSControl";
        }
    }
}
